S16-00 专题-JS-Storage
[TOC]
索引
基本属性
- Storage.length:
number
,只读,表示存储中键值对的总数。
基本方法
- Storage.getItem():
(key)
,返回key对应的value。 - Storage.setItem():
(key,value)
,将key和value添加到存储中。如果key存在则更新对应的值。 - Storage.removeItem():
(key)
,将该key从存储中删除。 - Storage.clear():
()
,清空存储中的所有key。 - Storage.key():
(index)
,根据索引获取存储对象中的指定键。
概述
Storage
Storage:是Web开发中用于在客户端(浏览器)持久化存储数据的技术,允许网页在不依赖服务器的情况下保存用户信息。
Storage主要提供了一种机制,可以让浏览器提供一种比cookie更直观的key、value存储方式。
Storage 分类:
- localStorage:是 HTML5 Web Storage API 的一部分,用于在客户端(浏览器)持久化存储键值对数据。
- sessionStorage:是 HTML5 Web Storage API 的一部分,用于在客户端(浏览器)临时存储键值对数据。
- Cookies:是网站存储在用户浏览器中的小型文本数据(通常小于 4KB),用于在客户端和服务端之间传递信息。
- IndexedDB:
图例:
对比localStorage、sessionStorage:
我们会发现localStorage和sessionStorage看起来非常的相似。
那么它们有什么区别呢?
验证一:关闭网页后重新打开,localStorage会保留,而sessionStorage会被删除;
验证二:在页面内实现跳转,localStorage会保留,sessionStorage也会保留;
验证三:在页面外实现跳转(打开新的网页),localStorage会保留,sessionStorage不会被保留;
localStorage
概述
localStorage:是 HTML5 Web Storage API 的一部分,用于在客户端(浏览器)持久化存储键值对数据。
核心特点:
- 持久性:数据除非手动删除(用户清除浏览器缓存或开发者调用API),否则永久保留。
- 同源策略:同一域名、协议、端口下的页面共享同一存储空间,不同源页面无法互相访问。
- 容量限制:通常为 5MB(不同浏览器可能略有差异),超出时会抛出错误。
- 仅支持字符串:键和值均为字符串,存储对象需序列化(如
JSON.stringify()
)。
API-localStorage
属性:
- storage.length:
number
,只读,表示存储中键值对的总数。
方法:
- storage.getItem():
(key)
,返回key对应的value。 - storage.setItem():
(key,value)
,将key和value添加到存储中。如果key存在则更新对应的值。 - storage.removeItem():
(key)
,将该key从存储中删除。 - storage.clear():
()
,清空存储中的所有key。 - storage.key():
(index)
,根据索引获取存储对象中的指定键。
sessionStorage
概述
sessionStorage:是 HTML5 Web Storage API 的一部分,用于在客户端(浏览器)临时存储键值对数据。
核心特点:
- 会话级存储:数据仅在当前浏览器标签页或窗口有效,关闭后自动清除。
- 同源策略:同一域名、协议、端口下的页面共享同一存储空间,但不同标签页的
sessionStorage
相互隔离。 - 容量限制:通常为 5MB(与
localStorage
一致),超出时会抛出错误。 - 仅支持字符串:键和值均为字符串,存储对象需序列化(如
JSON.stringify()
)。
API-sessionStorage
与 localStorage 一致。
Cookies
概述
Cookies:是网站存储在用户浏览器中的小型文本数据(通常小于 4KB),用于在客户端和服务端之间传递信息。
核心特点:
- 生命周期:可设置过期时间(
Expires
或Max-Age
),否则随浏览器关闭失效(会话Cookie)。 - 作用域:通过
Domain
和Path
控制可访问的域名和路径。 - 存储容量:每个 Cookie 最大 4KB,每个域名通常最多允许 50-150 个 Cookies。
- 自动携带:每次 HTTP 请求会自动附加同域名的 Cookies 到请求头的
Cookie
字段。
主要用途:
- 会话管理:保持用户登录状态、记录购物车内容等。
- 个性化:保存用户偏好(如语言、主题)。
- 行为跟踪:记录用户行为用于分析或广告定向(需符合隐私法规)。
语法格式
name=value; Expires=Wed, 21 Oct 2025 07:28:00 GMT; Max-Age=3600; Domain=example.com; Path=/; Secure; HttpOnly; SameSite=Lax
- 必需字段:
name=value
:键值对,内容需 URL 编码(如空格转为%20
)。
- 可选属性:
Expires
:过期时间(GMT 格式)。Max-Age
:存活时间(秒,优先级高于Expires
)。Domain
:指定可访问的域名(默认为当前域名,不包含子域名)。Path
:指定可访问的路径(默认为当前路径)。Secure
:仅通过 HTTPS 传输。HttpOnly
:禁止 JavaScript 访问,防 XSS 攻击。SameSite
:限制跨站请求携带 Cookie(值:Strict
/Lax
/None
)。
操作方式
不同环境有不同的操作 Cookies 的方法:
服务端操作
服务端设置:通过 Set-Cookie
HTTP 响应头创建或更新 Cookie:
HTTP/1.1 200 OK
Set-Cookie: user_id=123; Expires=Wed, 21 Oct 2025 07:28:00 GMT; Secure; HttpOnly
示例:服务端(Node.js)设置 Cookie
const http = require('http');
http.createServer((req, res) => {
res.setHeader('Set-Cookie', [
'user_id=123; HttpOnly; Max-Age=3600',
'theme=dark; SameSite=Lax'
]);
res.end('Cookies set!');
}).listen(3000);
客户端操作
客户端设置:通过 JS 中的 document.cookie
设置/获取 Cookies:
// 创建 Cookie(需手动编码)
document.cookie = "username=John%20Doe; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/; Secure";
// 读取所有 Cookies
const cookies = document.cookie; // 返回字符串 "cookie1=value1; cookie2=value2"
// 删除 Cookie(设置过期时间为过去)
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
示例:客户端读取 Cookie
// 解析 Cookies 为对象
const cookies = document.cookie.split('; ').reduce((acc, cookie) => {
const [name, value] = cookie.split('=');
acc[name] = decodeURIComponent(value);
return acc;
}, {});
console.log(cookies.user_id); // 输出 "123"
安全问题
CSRF(Cross-site Request Forgery,跨站请求伪造):攻击者诱导用户访问恶意页面,利用已登录的身份发起非法请求(如转账)。
防御:
- 设置
SameSite=Lax
(默认值,阻止跨站 POST 请求携带 Cookie)。 - 添加 CSRF Token 到请求中验证来源。
XSS(Cross-site scripting,跨站脚本攻击):恶意脚本窃取 Cookies。
防御:
- 敏感 Cookie 设置
HttpOnly
,禁止 JavaScript 访问。 - 对用户输入严格过滤和转义。
最佳安全实践:
敏感信息加密:
js// 服务端加密 Cookie 值 const encryptedValue = encryptAES('user123', secretKey); response.setHeader('Set-Cookie', `session=${encryptedValue}; HttpOnly; Secure`);
最小化 Cookie 使用:
- 避免存储敏感数据(如密码、身份证号)。
- 优先使用服务端 Session 管理身份验证。
隐私合规:遵循 GDPR、CCPA 等法规,明确告知用户并获取同意。
IndexedDB【
概述
IndexedDB:是浏览器提供的一种底层 异步 NoSQL 数据库,支持存储大量结构化数据(包括文件、Blob等),适用于复杂 Web 应用的客户端数据管理。
核心特点:
- 异步操作:所有读写操作非阻塞,通过事件或 Promise 处理结果。
- 事务支持:确保数据操作的原子性和一致性。
- 索引查询:支持基于键、索引的高效查询,类似关系型数据库。
- 大容量存储:浏览器动态分配存储空间,通常可达数百MB甚至更高。
- 同源策略:数据库按域名隔离,不同源页面无法互相访问。
进阶用法
封装Storage
基础封装
优化:存储对象类型
原生方法
优化:兼容local和session
TS封装Storage@
使用TS封装的Cache类
enum EStorage {
Local,
Session
}
/** 封装Storage */
class Cache {
storage: Storage
constructor(type: EStorage) {
this.storage = type === EStorage.Local ? localStorage : sessionStorage
}
getItem(key: string) {
const res = this.storage.getItem(key)
return res ? JSON.parse(res) : ''
}
setItem(key: string, value: any) {
this.storage.setItem(key, JSON.stringify(value || ''))
}
removeItem(key: string) {
this.storage.removeItem(key)
}
clear() {
this.storage.clear()
}
key(index: number) {
return this.storage.key(index)
}
addItem(key: string, value: any) {
let res = this.getItem(key)
if (!res) {
// 不存在key
this.storage.setItem(key, JSON.stringify(value || ''))
} else {
// 存在key
if (Array.isArray(res)) {
res = Array.isArray(value) ? [...res, ...value] : [...res, value]
} else if (isObjectLiteral(res)) {
res = { ...res, ...value }
} else {
res += value + ''
}
this.storage.setItem(key, JSON.stringify(res))
}
}
}
export const localCache = new Cache(EStorage.Local)
export const sessionCache = new Cache(EStorage.Session)
工具方法
/**
* 判断是否为对象字面量
* @param value 要判断的值
* @returns {boolean} 是否为对象字面量
*/
function isObjectLiteral(value: any) {
return Object.prototype.toString.call(value) === '[object Object]' && value !== null && !Array.isArray(value)
}
测试
// 测试
localCache.setItem('age', 27)
// localCache.setItem('name', 'zhangsan')
// localCache.setItem('user', { name: 'zhangsan', age: 18 })
// localCache.setItem('count', ['one', 'two', 'three', 'four'])
// console.log(localCache.getItem('age'))
// console.log(localCache.getItem('name'))
// console.log(localCache.getItem('user'))
// console.log(localCache.getItem('count'))
// 添加值
// localCache.addItem('info', {})
// localCache.addItem('user', { city: 'beijing' })
// localCache.addItem('count', ['eight'])
// localCache.addItem('count', 'seven')
localCache.addItem('age', 10) // '2710'